package demo3;

import java.text.SimpleDateFormat;
import java.util.*;

// 文件控制块（FCB）类，用于表示文件或目录的元信息
class FCB {
    String name;               // 文件或目录名称
    int size;                  // 文件大小（字节），目录为0
    int type;                  // 1 = 文件，2 = 目录
    String datetime;           // 创建时间
    List<FCB> children;        // 目录的子项列表（仅目录有）
    FCB parent;                // 父目录引用
    int startBlock = -1;       // 起始块号（仅文件使用）

    public FCB(String name, int type, FCB parent) {
        this.name = name;
        this.type = type;
        this.parent = parent;
        this.datetime = new SimpleDateFormat("yyyyMMdd HHmmss").format(new Date());
        if (type == 2) {
            this.size = 0;
            this.children = new ArrayList<>();
        }
    }

    public boolean isFile() { return this.type == 1; }
    public boolean isDirectory() { return this.type == 2; }
}

public class InMemoryFileSystem {
    static final int BLOCK_COUNT = 128;      // 总块数
    static final int BLOCK_SIZE = 64;        // 每块大小（字节）
    static int[] FAT = new int[BLOCK_COUNT]; // FAT表，每个元素指向下一个块号
    static boolean[] used = new boolean[BLOCK_COUNT]; // 标记每块是否被使用

    static FCB root = new FCB("", 2, null); // 根目录，类型为目录，父为null
    static FCB current = root;              // 当前目录，初始为根目录

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("内存文件系统启动，输入命令（输入 exit 退出）：");

        while (true) {
            System.out.print(getCurrentPath() + "> ");
            String input = scanner.nextLine().trim();
            if (input.equalsIgnoreCase("exit")) break;
            if (input.isEmpty()) continue;
            handleCommand(input); // 命令分发
        }

        scanner.close();
        System.out.println("文件系统已退出。");
    }

    // 获取当前路径字符串，例如：\test\sub\
    static String getCurrentPath() {
        if (current == root) return "\\";
        StringBuilder path = new StringBuilder();
        FCB temp = current;
        while (temp != null && temp != root) {
            path.insert(0, "\\" + temp.name);
            temp = temp.parent;
        }
        return path.toString() + "\\";
    }

    // 解析用户输入命令
    static void handleCommand(String input) {
        String[] parts = input.split("\\s+");
        String cmd = parts[0].toUpperCase();
        String name = parts.length >= 2 ? parts[1] : "";

        switch (cmd) {
            case "MD":
                if (!name.isEmpty()) makeDirectory(name); // 创建目录
                break;
            case "CD":
                if (!name.isEmpty()) changeDirectory(name); // 切换目录
                break;
            case "RD":
                if (!name.isEmpty()) removeDirectory(name); // 删除目录
                break;
            case "MK":
                if (!name.isEmpty()) makeFile(name); // 创建文件
                break;
            case "DEL":
                if (!name.isEmpty()) deleteFile(name); // 删除文件
                break;
            case "DIR":
                listDirectory(); // 列出目录内容
                break;
            case "SHOWBLOCKS":
                if (!name.isEmpty()) showFileBlocks(name); // 显示文件使用的块
                break;
            default:
                System.out.println("错误：无效命令");
        }
    }

    // 创建目录
    static void makeDirectory(String name) {
        if (findByName(name) != null) return;
        current.children.add(new FCB(name, 2, current));
    }

    // 创建文件，并在 FAT 表中分配块
    static void makeFile(String name) {
        if (findByName(name) != null) return;

        int fileSizeBlocks = new Random().nextInt(5) + 1; // 随机文件大小（块数）
        List<Integer> allocated = allocateBlocks(fileSizeBlocks); // 分配块
        if (allocated.isEmpty()) {
            System.out.println("错误：磁盘空间不足，无法创建文件");
            return;
        }

        FCB file = new FCB(name, 1, current);
        file.size = fileSizeBlocks * BLOCK_SIZE; // 计算文件大小（字节）
        file.startBlock = allocated.get(0); // 设置起始块号

        // 构建FAT链表关系
        for (int i = 0; i < allocated.size() - 1; i++) {
            FAT[allocated.get(i)] = allocated.get(i + 1);
        }
        FAT[allocated.get(allocated.size() - 1)] = -1; // 最后一块标记为-1

        current.children.add(file); // 加入当前目录
    }

    // 分配指定数量的块
    static List<Integer> allocateBlocks(int count) {
        List<Integer> blocks = new ArrayList<>();
        for (int i = 0; i < BLOCK_COUNT && blocks.size() < count; i++) {
            if (!used[i]) {
                used[i] = true;
                blocks.add(i);
            }
        }
        if (blocks.size() < count) {
            for (int b : blocks) used[b] = false; // 回滚已分配
            return Collections.emptyList();
        }
        return blocks;
    }

    // 删除文件，释放其FAT链占用的所有块
    static void deleteFile(String name) {
        FCB file = findByName(name);
        if (file != null && file.isFile()) {
            int block = file.startBlock;
            while (block != -1 && block < BLOCK_COUNT) {
                int next = FAT[block];
                FAT[block] = 0;         // 清除FAT指向
                used[block] = false;    // 标记为未使用
                block = next;           // 遍历下一块
            }
            current.children.remove(file); // 从目录中移除文件
        } else {
            System.out.println("错误：文件不存在");
        }
    }

    // 显示某个文件占用的所有块
    static void showFileBlocks(String name) {
        FCB file = findByName(name);
        if (file == null || !file.isFile()) {
            System.out.println("错误：文件不存在");
            return;
        }

        List<Integer> blocks = new ArrayList<>();
        int block = file.startBlock;
        while (block != -1 && block < BLOCK_COUNT) {
            blocks.add(block);
            block = FAT[block];
        }

        System.out.println("文件 '" + name + "' 占用的块: " + blocks);
    }

    // 切换当前目录（支持 .. 返回上一级）
    static void changeDirectory(String name) {
        if (name.equals("..")) {
            if (current.parent != null) current = current.parent;
            System.out.println(getCurrentPath());
            return;
        }
        FCB dir = findByName(name);
        if (dir != null && dir.isDirectory()) {
            current = dir;
            System.out.println(getCurrentPath());
        } else {
            System.out.println("错误：目录不存在");
        }
    }

    // 删除空目录
    static void removeDirectory(String name) {
        FCB dir = findByName(name);
        if (dir != null && dir.isDirectory()) {
            if (dir.children.isEmpty()) {
                current.children.remove(dir);
            } else {
                System.out.println("错误：目录非空");
            }
        } else {
            System.out.println("错误：目录不存在");
        }
    }

    // 列出当前目录下的所有文件和子目录
    static void listDirectory() {
        if (current.children.isEmpty()) return;
        for (FCB item : current.children) {
            String typeStr = item.isFile() ? "文件" : "目录";
            System.out.printf("%-10s %-6s %-6d %-15s 起始块: %d\n",
                    item.name, typeStr, item.size, item.datetime, item.startBlock);
        }
    }

    // 在当前目录中查找指定名称的文件或目录
    static FCB findByName(String name) {
        for (FCB item : current.children) {
            if (item.name.equalsIgnoreCase(name)) return item;
        }
        return null;
    }
}
